package xxl.signals.base 
{
	import flash.utils.Dictionary;
	import xxl.signals.core.IDeluxeSignal;
	import xxl.signals.core.IMapSignal;
	import xxl.signals.core.ISignal;
	import xxl.signals.core.ISlot;
	import xxl.signals.util.SignalUtil;
	
	/**
	 * 通过构造函数指定要使用的Signal类型
	 * @author XXL
	 */
	public class MapSignal implements IMapSignal 
	{
		protected const defaultKey:Object = { };
		protected var _valueClasses:Array;
		protected var _signalClass:Class;
		protected var signals:Dictionary = new Dictionary();
		
		public function MapSignal(signalClass:Class = null, ...valueClasses) 
		{
			_signalClass = signalClass ? signalClass : Signal;
			this.valueClasses = (valueClasses.length == 1 && valueClasses[0] is Array) ? valueClasses[0]:valueClasses;
		}
		
		protected function registerListenerToMap(key:Object, listener:Function, once:Boolean = false):ISlot
		{
			const signal:ISignal = getSignalByKey(key);
			if (once)
			{
				return signal.addOnce(listener);
			}
			return signal.add(listener);
		}
		
		/* INTERFACE xxl.signals.core.IMapSignal */
		
		public function addToMap(key:Object, listener:Function):ISlot 
		{
			return registerListenerToMap(key, listener, false);
		}
		
		public function addOnceToMap(key:Object, listener:Function):ISlot 
		{
			return registerListenerToMap(key, listener, true);
		}
		
		public function getNumListenersByKey(key:Object):int 
		{
			var signal:ISignal = signals[key];
			if (!signal)
			{
				return 0;
			}
			return signal.numListeners;
		}
		
		public function add(listener:Function):ISlot 
		{
			return registerListenerToMap(defaultKey, listener);
		}
		
		public function addOnce(listener:Function):ISlot 
		{
			return registerListenerToMap(defaultKey, listener, true);
		}
		
		public function dispatch(...valueObjects):void 
		{
			const key:Object = valueObjects[0]?valueObjects[0]:defaultKey;
			const signal:ISignal = signals[key];
			if (signal)
			{
				SignalUtil.Apply(signal, signal.dispatch, valueObjects);
				if (signal.numListeners <= 0)
				{
					delete signals[key];
				}
			}
			if (key != defaultKey)
			{
				const defaultSignal:ISignal = signals[defaultKey];
				if (defaultSignal)
				{
					SignalUtil.Apply(defaultSignal, defaultSignal.dispatch, valueObjects);
					if (defaultSignal.numListeners <= 0)
					{
						delete signals[defaultSignal];
					}
				}
			}
		}
		
		public function remove(listener:Function):ISlot 
		{
			return removeFromMap(defaultKey, listener);
		}
		
		public function removeAll():void 
		{
			for each(var signal:ISignal in signals)
			{
				signal.removeAll();
			}
			signals = new Dictionary();
		}
		
		public function removeAllByKey(key:Object):void
		{
			const signal:ISignal = signals[key];
			if (signal)
			{
				signal.removeAll();
				delete signals[key];
			}
		}
		
		public function removeFromMap(key:Object, listener:Function):ISlot 
		{
			const signal:ISignal = signals[key];
			if (signal)
			{
				const slot:ISlot = signal.remove(listener);
				if (signal.numListeners <= 0)
				{
					delete signals[key];
				}
				return slot;
			}
			return null;
		}
		
		public function getSignalByKey(key:Object):ISignal
		{
			var signal:ISignal = signals[key];
			if (!signal)
			{
				signal = new _signalClass();
				signal.valueClasses = valueClasses;
				signals[key] = signal;
			}
			return signal;
		}
		
		public function get valueClasses():Array 
		{
			return _valueClasses;
		}
		
		public function set valueClasses(value:Array):void 
		{
			for each(var signal:ISignal in signals)
			{
				signal.valueClasses = value;
			}
			_valueClasses = value ? value.concat() : [];
		}
		
		public function get numListeners():int 
		{
			var count:int = 0;
			for each(var signal:ISignal in signals)
			{
				count += signal.numListeners;
			}
			return count;
		}
		
		
	}

}